package com.osdp.common.util;

import org.apache.commons.io.IOUtils;
import org.jose4j.base64url.internal.apache.commons.codec.binary.Base64;
import org.springframework.core.io.ClassPathResource;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * 获取公钥、私钥类
 */
public class RSAUtil {
    private static Cipher cipher;

    static{
        try {
            cipher = Cipher.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成公钥与私钥方法，生成后经过base64编码，输出字符串密钥。
     * 可使用main方法调用，生成后，放到xx-/private.pem文件和xx-public.pem文件
     * @return
     * @throws Exception
     */
    public static RSAKeyPair generateKeyPair() throws Exception{
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        // 密钥位数
        keyPairGen.initialize(2048);
        // 密钥对
        KeyPair keyPair = keyPairGen.generateKeyPair();
        // 公钥
        PublicKey publicKey = keyPair.getPublic();
        // 私钥
        PrivateKey privateKey = keyPair.getPrivate();

        String publicKeyString = getKeyString(publicKey);

        String privateKeyString = getKeyString(privateKey);

        return new RSAKeyPair(publicKeyString,privateKeyString);

    }

    /**
     * 获取密钥字符串
     * @return
     * @throws IOException
     * 生成RSA 密钥方法：
     * 1、安装openssl
     * 2、执行指令：openssl genrsa -out private.pem 2048
     */
    private static String getPrivateKeyString() throws IOException {
        ClassPathResource classPathResource = new ClassPathResource("private_key/private.pem");
        return IOUtils.toString(classPathResource.getInputStream(), Charset.defaultCharset());

    }

    /**
     * 获取公钥字符串
     * @return
     * @throws IOException
     * 生成RSA 公钥方法：
     * 1、安装 openssl
     * 2、执行指令：openssl rsa -in private.pem -outform PEM -pubout -out public.pem
     */
    private static String getPEMPublicKeyString() throws IOException {
        ClassPathResource classPathResource = new ClassPathResource("public_key/public.pem");
        return IOUtils.toString(classPathResource.getInputStream(),Charset.defaultCharset());
    }


    /**
     * 获取PrivateKey对象
     * @return
     */
    public static PrivateKey getPrivateKey() throws Exception {
        String key = getPrivateKeyString();
        return getPrivateKey(key);
    }

    /**
     * 获取公钥
     * @return
     * @throws Exception
     */
    public static PublicKey getPublicKey() throws Exception {
        String key = getPEMPublicKeyString();
        return getPublicKey(key);
    }

    /**
     * 得到公钥
     *
     * @param key
     *            密钥字符串（经过base64编码）
     * @throws Exception
     */
    public static PublicKey getPublicKey(String key) throws Exception {
        byte[] keyBytes;
        keyBytes = Base64.decodeBase64(key);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }

    /**
     * 得到私钥
     *
     * @param key
     *            密钥字符串（经过base64编码）
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(String key) throws Exception {
        byte[] keyBytes;
        keyBytes = Base64.decodeBase64(key);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }

    /**
     * 得到密钥字符串（经过base64编码）
     *
     * @return
     */
    public static String getKeyString(Key key) throws Exception {
        byte[] keyBytes = key.getEncoded();
        String s = Base64.encodeBase64String(keyBytes);
        return s;
    }

    /**
     * 公钥加密
     * @param plainText
     * @return
     */
    public static String encrypt(String plainText){
        try {
            String publicKey = getPEMPublicKeyString();
            return encrypt(publicKey,plainText);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 使用公钥对明文进行加密
     * @param publicKey      公钥
     * @param plainText      明文
     * @return
     */
    public static String encrypt(String publicKey, String plainText){
        try {
            cipher.init(Cipher.ENCRYPT_MODE,getPublicKey(publicKey));
            byte[] enBytes = cipher.doFinal(plainText.getBytes());
            return Base64.encodeBase64String(enBytes);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 私钥解密
     * @param enStr
     * @return
     */
    public static String decrypt(String enStr){
        try {
            String privateKey = getPrivateKeyString();
            return decrypt(privateKey,enStr);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 使用私钥对密文进行解密
     * @param privateKey       私钥
     * @param enStr            密文
     * @return
     */
    public static String decrypt(String privateKey, String enStr){
        try {
            cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(privateKey));
            byte[] deBytes = cipher.doFinal(Base64.decodeBase64(enStr));
            return new String(deBytes);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) throws Exception {
        RSAKeyPair rsaKeyPair = RSAUtil.generateKeyPair();

        String publicKey = rsaKeyPair.getPublicKey();
        System.out.println("publicKey:"+ publicKey);
        String privateKey = rsaKeyPair.getPrivateKey();

        System.out.println("privateKey:" + privateKey);
//        String aaaaa = RSAUtil.encrypt("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCFkkx17tdVC9AL6aLEuUMuc5vaky6qE3Wk/WNKdEsI8eSKDZUOcPJWbfMPNjj+cA7N0Jt2LMfQBfqScv31jkRk+X8xPy0toXouggcK9/Ljv8JIQ7cKPDez/yzKJ/G7AxYax784cqAml6hRc5+xZ9G+7pmtOgDW+R/yhRxWht3lFwIDAQAB", "aaaaa");
////
//        String decrypt = RSAUtil.decrypt("MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIWSTHXu11UL0AvposS5Qy5zm9qTLqoTdaT9Y0p0Swjx5IoNlQ5w8lZt8w82OP5wDs3Qm3Ysx9AF+pJy/fWORGT5fzE/LS2hei6CBwr38uO/wkhDtwo8N7P/LMon8bsDFhrHvzhyoCaXqFFzn7Fn0b7uma06ANb5H/KFHFaG3eUXAgMBAAECgYBp9Y2sPGUbtTw8RwH1VxYhQlrPwNRS3Q8FbHEYvjpMBUAL+AxXoWfNAnm/hn8d8Jz9zk+VJp73udZ12Lz3z/0Wf+e8KD07DuP9NGrG4QwTid7JXrA/Xp+yXb38n3wCcvluMalh+QXaQnB0fDjy2PQSQJTixEE1YLoh9qJH0SpnQQJBAPUsRGYAW50lcVwpkVZwlIDzL9NSerKGYSFTCFL0SQWr/YJyZ7NLo3pFp9kfNOkmmll9uFmxrJKoZR09wRDhZXcCQQCLeFplNIt7tgs8zUDs9OLPxLvjTIukvZMwLh2IEnn8m4guxjirPZbJAxSwnnB6/ZikBg/sd44YIvPeMeDEpeVhAkA/Ebsqri7jFw25Uqwjm2RoY6bK6u3LXQxBgVWj2VmrjtnxI7MPiYatXpvWG9QFojuUh+XTlQQ62fzg79DpocHzAkAtOpFuApU9QDLyu8lTTrMDF9SqiJc8jHHgDQRsrTk8DyAhswyLk8SDWWlrQWZOrFDE2GZvk/HTp/oX02sFuprhAkEAzF01LgvbhjY6FILdJLKzDeqDwiOZ6NmXewxI+CBfpMoycq5k6HP9sJoW07I3aKx5o8T1hMw51YEyIxalpyRbHg==", aaaaa);
//        System.out.println(decrypt);


    }
}
